package com.loto.insurance.oem.web.service.common;

import java.math.BigDecimal;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.DefaultTransactionDefinition;

import com.loto.insurance.oem.web.db.mapper.CustFeeFlowMapper;
import com.loto.insurance.oem.web.db.mapper.CustFeeInitMapper;
import com.loto.insurance.oem.web.db.mapper.CustInfoMapper;
import com.loto.insurance.oem.web.db.mapper.OrderFlowMapper;
import com.loto.insurance.oem.web.db.mapper.OrderInfoMapper;
import com.loto.insurance.oem.web.db.mapper.OthersMapper;
import com.loto.insurance.oem.web.db.mapper.PolicyFlowMapper;
import com.loto.insurance.oem.web.db.mapper.PolicyInfoAirMapper;
import com.loto.insurance.oem.web.db.mapper.PolicyInfoMapper;
import com.loto.insurance.oem.web.db.mapper.PolicyInfoTravelMapper;
import com.loto.insurance.oem.web.entity.CustFeeFlow;
import com.loto.insurance.oem.web.entity.CustFeeInit;
import com.loto.insurance.oem.web.entity.CustInfo;
import com.loto.insurance.oem.web.entity.OrderFlow;
import com.loto.insurance.oem.web.entity.OrderInfo;
import com.loto.insurance.oem.web.entity.PolicyFlow;
import com.loto.insurance.oem.web.entity.PolicyInfo;
import com.loto.insurance.oem.web.entity.PolicyInfoAir;
import com.loto.insurance.oem.web.entity.PolicyInfoTravel;
import com.loto.insurance.oem.web.entity.ajax.BaseJson;
import com.loto.insurance.oem.web.entity.config.OEMConfig;
import com.loto.insurance.oem.web.entity.config.PayAccount;
import com.loto.insurance.oem.web.entity.webservice.FeeInit;
import com.loto.insurance.oem.web.entity.webservice.PaidOrder;
import com.loto.insurance.oem.web.entity.webservice.PaidPolicy;
import com.loto.insurance.oem.web.entity.webservice.PayInfo;
import com.loto.insurance.oem.web.entity.webservice.SimplePolicyInfo;
import com.loto.insurance.oem.web.enumeration.ConfigFileEnum;
import com.loto.insurance.oem.web.enumeration.ControllerPropertyEnum;
import com.loto.insurance.oem.web.enumeration.FeeTypeEnum;
import com.loto.insurance.oem.web.enumeration.InsTypeEnum;
import com.loto.insurance.oem.web.enumeration.OrderStatusEnum;
import com.loto.insurance.oem.web.enumeration.PayChannelEnum;
import com.loto.insurance.oem.web.enumeration.PayForEnum;
import com.loto.insurance.oem.web.enumeration.PaymentStatusEnum;
import com.loto.insurance.oem.web.enumeration.PolicyFeeStatusEnum;
import com.loto.insurance.oem.web.enumeration.PolicyStatusEnum;
import com.loto.insurance.oem.web.utils.Config;
import com.loto.utils.DateUtils;
import com.loto.utils.Http;
import com.loto.utils.XML;

@Service
public class PolicyOrder implements Order {
  static Logger logger = LogManager.getLogger(PolicyOrder.class);

  @Autowired
  OrderInfoMapper orderInfoMapper;

  @Autowired
  OthersMapper othersMapper;

  @Autowired
  CustFeeInitMapper custFeeInitMapper;

  @Autowired
  CustFeeFlowMapper custFeeFlowMapper;

  @Autowired
  CustInfoMapper custInfoMapper;

  @Autowired
  OrderFlowMapper orderFlowMapper;

  @Autowired
  PolicyInfoAirMapper policyInfoAirMapper;

  @Autowired
  PolicyInfoTravelMapper policyInfoTravelMapper;

  @Autowired
  PolicyFlowMapper policyFlowMapper;

  @Autowired
  PolicyInfoMapper policyInfoMapper;

  @Autowired
  DataSourceTransactionManager transactionManager;

  @Autowired
  DefaultTransactionDefinition def;

  // 支付类型为第三方
  // 收款方为平台
  // 分润付款方：平台；分润收款方：OEM；分润金额：订单实际金额-订单结算金额
  // 收款方为OEM
  // 分润付款方：OEM；分润收款方：平台；分润金额：订单结算金额

  // 支付类型为余额支付
  // 若OEM在平台中的余额足够
  // 平台中扣除相应余额（订单结算金额）；OEM中将订单实际金额-订单结算金额的金额以余额方式给到OEM的admin账号
  // 若OEM在平台中的余额不够
  // 不能进行余额支付

  // 备注：1、OEM上不提供充值功能
  // 2、每次发起支付前要将订单信息上送至平台并返回分润详情
  // 3、OEM在平台完成充值后，OEMD在平台上的余额增加，OEM的admin账号获得相应的金额
  // 4、OEM在平台的余额变小时，应扣除OEM的admin相应余额，若不够扣，则将OEM中所有账号的余额扣至admin再一并扣回；
  // 5、每天核对检查平台中记录的余额与OEM中的余额是否匹配
  // 6、OEM给用户修改余额时，所有用户的余额总和不能大于OEM在平台的余额

  // 退保
  // 若OEM在平台的余额及OEM的admin余额都>=分润金额（分润金额=订单实际金额-订单结算金额），则将保单结算金额加到OEM在平台的余额，
  // 同时OEM的admin账号获得相应金额，OEM的admin账号再扣除保单实际金额，该保单实际金额返还到用户的账号
  // 若余额不够，则不能退保

  @Override
  public CustFeeInit prepairOrder(long custId, long orderId,
	  PayChannelEnum channel) {
	// 订单验证
	Config config = new Config();
	OEMConfig configFile = config.getConfigFile(ConfigFileEnum.OEMCONFIG,
	    OEMConfig.class);
	Map<String, Object> params = new HashMap<String, Object>();
	params.put("orderId", orderId);
	params.put("custId", custId);
	OrderInfo orderInfo = orderInfoMapper.findOrderPayInfoByCust(params);
	if (orderInfo != null && configFile != null
	    && configFile.getOemPayAccount().getAlipay().getAccount() != null) {

	  PayAccount account = configFile.getOemPayAccount().getAlipay()
		  .getAccount();

	  String outPayNo = DateUtils.nowToCompactString()
		  + othersMapper.getIndex() + "-" + orderInfo.getOrderNo();
	  BigDecimal fee = orderInfo.getOrderRealAmount();

	  BigDecimal rate = new BigDecimal(0.012);
	  rate = account.getRate();
	  BigDecimal payFee = fee.divide(new BigDecimal(1).subtract(rate), 2,
		  BigDecimal.ROUND_UP);

	  CustFeeInit feeInit = new CustFeeInit();
	  feeInit.setInitChannel(channel.getName());
	  feeInit.setInitChangeFee(fee);
	  feeInit.setInitCustFid(custId);
	  feeInit.setInitFor(PayForEnum.ORDER.getIndex());
	  feeInit.setInitOutPayDesc("订单支付：" + orderInfo.getOrderNo());
	  feeInit.setInitOutPayNo(outPayNo);
	  feeInit.setInitPayFee(payFee);
	  feeInit.setInitRelatedFid(orderId);
	  feeInit.setInitType(FeeTypeEnum.CONSUME.getIndex());
	  feeInit.setInitRoyaltyFee(new BigDecimal(0));

	  // TODO 预留去平台取收款方信息
	  PayInfo payInfo = null;
	  String payer = "PLATFORM";
	  BigDecimal usefulFee = new BigDecimal(0);
	  // 后台的账号信息
	  String partner = "";
	  String sellerEmail = "";
	  String secret = "";
	  try {
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("id", configFile.getOemId());
		paramMap.put("acc", configFile.getOemAcc());
		paramMap.put("pin", configFile.getOemPin());
		String xmlResponse = Http.doPost(configFile.getOemPlatform()
		    + "/webservice/getpayinfo.service", paramMap);
		logger.info(xmlResponse);
		payInfo = XML.fromXML(xmlResponse, PayInfo.class);
		if (payInfo != null && !payInfo.getPayer().isEmpty()) {
		  payer = payInfo.getPayer();
		  partner = payInfo.getPartner();
		  sellerEmail = payInfo.getSellerEmail();
		  secret = payInfo.getSecret();
		  usefulFee = payInfo.getUsefulFee();
		}
	  } catch (Exception e) {
		e.printStackTrace();
		return null;
	  }

	  if (channel == PayChannelEnum.BALANCE) { // 余额支付
		feeInit.setInitPayFee(fee);
		feeInit.setInitRoyaltyPayer("PLATFORM");
		if (usefulFee.compareTo(orderInfo.getOrderSettleAmount()) >= 0) {// 若OEM在平台中的余额足够
		  if (orderInfo.getOrderRealAmount().compareTo(
			  orderInfo.getOrderSettleAmount()) > 0) {
			feeInit.setInitRoyaltyPayee("OEM");
			feeInit.setInitRoyaltyFee(orderInfo.getOrderRealAmount().remainder(
			    orderInfo.getOrderSettleAmount()));
			feeInit.setInitRoyaltyMemo("分润，订单号：" + orderInfo.getOrderNo());
		  }
		} else // 若OEM在平台中的余额不够,不能进行余额支付
		{
		  return null;
		}
	  } else { // 第三方支付
		switch (payer) {
		  case "PLATFORM": // 平台收款
			// TODO
			feeInit.setPartner(partner);
			feeInit.setKey(secret);
			feeInit.setEmail(sellerEmail);
			feeInit.setInitRoyaltyPayer(sellerEmail);

			if (orderInfo.getOrderRealAmount().compareTo(
			    orderInfo.getOrderSettleAmount()) > 0) {
			  feeInit.setInitRoyaltyPayee(account.getEmail());
			  feeInit.setInitRoyaltyFee(orderInfo.getOrderRealAmount()
				  .remainder(orderInfo.getOrderSettleAmount()));
			  feeInit.setInitRoyaltyMemo("分润，订单号：" + orderInfo.getOrderNo());
			}
			break;
		  case "OEM": // OEM收款
			feeInit.setPartner(account.getPartner());
			feeInit.setKey(account.getSecret());
			feeInit.setEmail(account.getEmail());
			feeInit.setInitRoyaltyPayer(account.getEmail());

			feeInit.setInitRoyaltyPayee(sellerEmail);
			feeInit.setInitRoyaltyFee(orderInfo.getOrderSettleAmount());
			feeInit.setInitRoyaltyMemo("分润，订单号：" + orderInfo.getOrderNo());
			break;
		}
	  }

	  // 插入数据
	  long initId = custFeeInitMapper.insertCustFeeInit(feeInit);
	  if (initId > 0)
		return feeInit;
	  else
		return null;
	}
	return null;
  }

  @Override
  public boolean doPay(CustFeeInit feeInit) {
	// 判断交易号是否已存在
	if (custFeeFlowMapper.findFlowByPayNo(feeInit.getInitPayNo()).size() == 0) {
	  if (feeInit.getInitFor() == PayForEnum.ORDER.getIndex()) {
		// 判断该ID是否已支付
		OrderInfo orderInfo = orderInfoMapper.findOrderPayInfoById(feeInit
		    .getInitRelatedFid());
		CustInfo custInfo = custInfoMapper.findUsefulfeeById(feeInit
		    .getInitCustFid());
		BigDecimal fee = feeInit.getInitChangeFee();
		BigDecimal usefulFee = custInfo.getCustUsefulFee();
		if (orderInfo != null) { // 若未支付，添加FLOW，修改订单状态，发起投保动作
		  long orderId = feeInit.getInitRelatedFid();

		  TransactionStatus status = transactionManager.getTransaction(def);
		  try {
			// (1)添加FEE_FLOW
			CustFeeFlow consumeFeeFlow = new CustFeeFlow();
			if (feeInit.getInitChannel() != PayChannelEnum.BALANCE.getName()) {
			  // 一笔充值
			  CustFeeFlow feeFlow = new CustFeeFlow();
			  feeFlow.setFlowAfterFee(usefulFee.add(fee));
			  feeFlow.setFlowBeforeFee(usefulFee);
			  feeFlow.setFlowChangedFee(fee);
			  feeFlow.setFlowChannel(feeInit.getInitChannel());
			  feeFlow.setFlowCreditedOn(feeInit.getInitCreditedOn());
			  feeFlow.setFlowCustFid(feeInit.getInitCustFid());
			  feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			  feeFlow.setFlowFor(feeInit.getInitFor());
			  feeFlow.setFlowMemo(feeInit.getInitOutPayDesc());
			  feeFlow.setFlowOutPayNo(feeInit.getInitOutPayNo());
			  feeFlow.setFlowPayNo(feeInit.getInitPayNo());
			  feeFlow.setFlowRelatedFid(orderId);
			  feeFlow.setFlowType(FeeTypeEnum.SUPPLEMENT.getIndex());
			  custFeeFlowMapper.insertCustFeeFlow(feeFlow);

			  // 一笔消费
			  consumeFeeFlow.setFlowAfterFee(usefulFee);
			  consumeFeeFlow.setFlowBeforeFee(usefulFee.add(fee));
			  consumeFeeFlow.setFlowChangedFee(fee.subtract(fee
				  .multiply(new BigDecimal(2))));
			  consumeFeeFlow.setFlowChannel(feeInit.getInitChannel());
			  consumeFeeFlow.setFlowCreditedOn(feeInit.getInitCreditedOn());
			  consumeFeeFlow.setFlowCustFid(feeInit.getInitCustFid());
			  consumeFeeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			  consumeFeeFlow.setFlowFor(feeInit.getInitFor());
			  consumeFeeFlow.setFlowMemo(feeInit.getInitOutPayDesc());
			  consumeFeeFlow.setFlowOutPayNo(feeInit.getInitOutPayNo());
			  consumeFeeFlow.setFlowPayNo(feeInit.getInitPayNo());
			  consumeFeeFlow.setFlowRelatedFid(orderId);
			  consumeFeeFlow.setFlowType(FeeTypeEnum.CONSUME.getIndex());
			} else if (usefulFee.compareTo(orderInfo.getOrderSettleAmount()) > -1) {
			  // 一笔消费
			  consumeFeeFlow.setFlowAfterFee(usefulFee.subtract(fee));
			  consumeFeeFlow.setFlowBeforeFee(usefulFee);
			  consumeFeeFlow.setFlowChangedFee(fee.subtract(fee
				  .multiply(new BigDecimal(2))));
			  consumeFeeFlow.setFlowChannel(feeInit.getInitChannel());
			  consumeFeeFlow.setFlowCreditedOn(feeInit.getInitCreditedOn());
			  consumeFeeFlow.setFlowCustFid(feeInit.getInitCustFid());
			  consumeFeeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			  consumeFeeFlow.setFlowFor(feeInit.getInitFor());
			  consumeFeeFlow.setFlowMemo(feeInit.getInitOutPayDesc());
			  consumeFeeFlow.setFlowOutPayNo(feeInit.getInitOutPayNo());
			  consumeFeeFlow.setFlowPayNo(feeInit.getInitPayNo());
			  consumeFeeFlow.setFlowRelatedFid(orderId);
			  consumeFeeFlow.setFlowType(FeeTypeEnum.CONSUME.getIndex());

			  // 修改余额
			  Map<String, Object> params = new HashMap<String, Object>();
			  params.put("custId", feeInit.getInitCustFid());
			  params.put("changedFee",
				  fee.subtract(fee.multiply(new BigDecimal(2))));
			  custInfoMapper.updateUsefulfeeById(params);
			} else {
			  transactionManager.rollback(status);
			  return false;
			}
			long flowId = custFeeFlowMapper.insertCustFeeFlow(consumeFeeFlow);
			if (flowId <= 0) {
			  transactionManager.rollback(status);
			  return false;
			}
			// (2)修改订单状态为支付成功
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("orderId", orderId);
			params.put("orderStatusFid", OrderStatusEnum.PAID.getIndex());
			params.put("orderPaidOn", feeInit.getInitCreditedOn());
			orderInfoMapper.updateOrderStatusById(params);

			// (3)创建订单流
			OrderFlow orderFlow = new OrderFlow();
			orderFlow.setFlowOrderFid(orderId);
			orderFlow.setFlowOperFid(0);
			orderFlow.setFlowOrderStatusFid(OrderStatusEnum.PAID.getIndex());
			orderFlow.setFlowOrderStatus(OrderStatusEnum.PAID.getName());
			orderFlow.setFlowMemo(OrderStatusEnum.PAID.getDesc());
			orderFlowMapper.insertOrderFlow(orderFlow);
			// (4)修改保单状态和费用状态为支付成功
			params = new HashMap<String, Object>();
			params.put("orderId", orderId);
			params.put("feeStatusId", PolicyFeeStatusEnum.PAID.getIndex());

			Map<String, Object> statusParams = new HashMap<String, Object>();
			statusParams.put("orderId", orderId);
			statusParams.put("statusId", PolicyStatusEnum.PAID.getIndex());

			Map<String, Object> policyParams = new HashMap<String, Object>();
			policyParams.put("orderId", orderId);
			policyParams.put("flowInsTypeFid",
			    orderInfo.getOrderProductTypeFid());
			policyParams.put("flowPolicyStatusFid",
			    PolicyStatusEnum.PAID.getIndex());
			policyParams.put("flowPolicyStatus",
			    PolicyStatusEnum.PAID.getName());
			policyParams.put("flowFeeFlowFid", flowId);
			policyParams.put("flowMemo", PolicyStatusEnum.PAID.getDesc());
			if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
			    .getIndex()) {
			  policyInfoAirMapper.updatePolicyFeeStatusByOrderId(params);
			  policyInfoAirMapper.updatePolicyStatusByOrderId(statusParams);
			  // (5)批量创建保单流
			  policyFlowMapper.insertAirPolicyFlowBat(policyParams);
			} else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
			    .getIndex()) {
			  policyInfoTravelMapper.updatePolicyFeeStatusByOrderId(params);
			  policyInfoTravelMapper.updatePolicyStatusByOrderId(statusParams);
			  // (5)批量创建保单流
			  policyFlowMapper.insertTravelPolicyFlowBat(policyParams);
			}
			transactionManager.commit(status);

			// TODO 通知大后台已支付
			// 餘額支付時， 平台中扣除相应余额（订单结算金额）；
			Config config = new Config();
			OEMConfig configFile = config.getConfigFile(
			    ConfigFileEnum.OEMCONFIG, OEMConfig.class);
			try {
			  FeeInit init = new FeeInit();
			  init.setCustFeeInit(feeInit);
			  String xmlRequest = XML.toXML(init, FeeInit.class);
			  logger.info(xmlRequest);
			  Map<String, String> paramMap = new HashMap<String, String>();
			  paramMap.put("content", xmlRequest);
			  String xmlResponse = Http.doPost(configFile.getOemPlatform()
				  + "/webservice/orderpay.service", paramMap);
			  logger.info(xmlResponse);
			  PaidOrder paidOrder = XML.fromXML(xmlResponse, PaidOrder.class);
			  if (paidOrder != null && paidOrder.isOk()) {
				// 更新fee_flow的platform
				Map<String, Object> flowParams = new HashMap<String, Object>();
				flowParams.put("flowOutPayNo", feeInit.getInitOutPayNo());
				flowParams.put("flowPlatformId", paidOrder.getMsg());
				custFeeFlowMapper.updatePlatformIdByOutPayNo(flowParams);

				// 更新订单信息
				params = new HashMap<String, Object>();
				params.put("orderId", orderId);
				params.put("orderStatusFid",
				    OrderStatusEnum.INSURED_SUC.getIndex());
				orderInfoMapper.updateOrderStatusById(params);

				// 增加订单流
				orderFlow = new OrderFlow();
				orderFlow.setFlowOrderFid(orderId);
				orderFlow.setFlowOperFid(0);
				orderFlow.setFlowOrderStatusFid(OrderStatusEnum.INSURED_SUC
				    .getIndex());
				orderFlow.setFlowOrderStatus(OrderStatusEnum.INSURED_SUC
				    .getName());
				orderFlow.setFlowMemo(OrderStatusEnum.INSURED_SUC.getDesc());
				orderFlowMapper.insertOrderFlow(orderFlow);

				// 更新保单信息及创建保单流
				if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
				    .getIndex()) {
				  updatePolicyAir(orderId, paidOrder.getPolicyList());
				} else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
				    .getIndex()) {
				  updatePolicyTravel(orderId, paidOrder.getPolicyList());
				}
			  }
			} catch (Exception e) {
			  e.printStackTrace();
			}

			return true;
		  } catch (Exception ex) {
			ex.printStackTrace();
			transactionManager.rollback(status);
		  }

		} else if (feeInit.getInitChannel() != PayChannelEnum.BALANCE.getName()) { // 若已支付，按充值计
		  TransactionStatus status = transactionManager.getTransaction(def);
		  try {
			// 添加FEE_FLOW
			CustFeeFlow feeFlow = new CustFeeFlow();
			feeFlow.setFlowAfterFee(usefulFee.add(fee));
			feeFlow.setFlowBeforeFee(usefulFee);
			feeFlow.setFlowChangedFee(fee);
			feeFlow.setFlowChannel(feeInit.getInitChannel());
			feeFlow.setFlowCreditedOn(feeInit.getInitCreditedOn());
			feeFlow.setFlowCustFid(feeInit.getInitCustFid());
			feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			feeFlow.setFlowFor(feeInit.getInitFor());
			feeFlow.setFlowMemo(feeInit.getInitMemo());
			feeFlow.setFlowOutPayNo(feeInit.getInitOutPayNo());
			feeFlow.setFlowPayNo(feeInit.getInitPayNo());
			feeFlow.setFlowRelatedFid(0);
			feeFlow.setFlowType(FeeTypeEnum.SUPPLEMENT.getIndex());
			custFeeFlowMapper.insertCustFeeFlow(feeFlow);
			// 修改余额
			Map<String, Object> params = new HashMap<String, Object>();
			params.put("custId", feeInit.getInitCustFid());
			params.put("changedFee", fee);
			custInfoMapper.updateUsefulfeeById(params);

			transactionManager.commit(status);
		  } catch (Exception ex) {
			transactionManager.rollback(status);
		  }
		}
	  } else if (feeInit.getInitFor() == PayForEnum.INVOICE.getIndex()) {

	  }
	}
	return false;
  }

  private void updatePolicyAir(long orderId, List<PaidPolicy> paidPolicyList) {
	for (PaidPolicy p : paidPolicyList) {
	  TransactionStatus status = transactionManager.getTransaction(def);
	  try {
		// 更新保单信息
		Map<String, Object> params = new HashMap<String, Object>();
		params = new HashMap<String, Object>();
		params.put("policyOutOrderNo", p.getPolicyOutOrderNo());
		params.put("orderId", orderId);

		PolicyStatusEnum statusEnum = PolicyStatusEnum.INSURED_FAILS;
		String statusDesc = statusEnum.getDesc();
		if (p.getInsNo() != null && !p.getInsNo().isEmpty()) { // 投保成功
		  statusEnum = PolicyStatusEnum.INSURED_SUC;
		  statusDesc = statusEnum.getDesc();
		  params.put("statusId", statusEnum.getIndex());
		  params.put("policyTradeOrderNo", p.getPolicyTradeOrderNo());
		  params.put("policyNo", p.getInsNo());
		  policyInfoAirMapper.updatePolicyByOutOrderNoOrderId(params);

		} else {
		  params.put("statusId", statusEnum.getIndex());
		  policyInfoAirMapper.updatePolicyStatusByOutOrderNoOrderId(params);
		  statusDesc = p.getMsg();
		}
		params = new HashMap<String, Object>();
		params.put("policyOutOrderNo", p.getPolicyOutOrderNo());
		params.put("orderId", orderId);
		PolicyInfoAir pInfo = policyInfoAirMapper
		    .findPolicyInfoByOutOrderNoOrderId(params);
		// 创建保单流
		PolicyFlow policyFlow = new PolicyFlow();
		policyFlow.setFlowInsTypeFid(InsTypeEnum.AIR.getIndex());
		policyFlow.setFlowPolicyFid(pInfo.getPolicyId());
		policyFlow.setFlowOperFid(0);
		policyFlow.setFlowPolicyStatusFid(statusEnum.getIndex());
		policyFlow.setFlowPolicyStatus(statusEnum.getName());
		policyFlow.setFlowMemo(statusDesc);
		policyFlowMapper.insertPolicyFlow(policyFlow);

		transactionManager.commit(status);

	  } catch (Exception ex) {
		ex.printStackTrace();
		transactionManager.rollback(status);
	  }
	}
  }

  private void updatePolicyTravel(long orderId, List<PaidPolicy> paidPolicyList) {
	for (PaidPolicy p : paidPolicyList) {
	  TransactionStatus status = transactionManager.getTransaction(def);
	  try {
		// 更新保单信息
		Map<String, Object> params = new HashMap<String, Object>();
		params = new HashMap<String, Object>();
		params.put("policyOutOrderNo", p.getPolicyOutOrderNo());
		params.put("orderId", orderId);

		PolicyStatusEnum statusEnum = PolicyStatusEnum.INSURED_FAILS;
		String statusDesc = statusEnum.getDesc();
		if (p.getInsNo() != null && !p.getInsNo().isEmpty()) { // 投保成功
		  statusEnum = PolicyStatusEnum.INSURED_SUC;
		  statusDesc = statusEnum.getDesc();
		  params.put("statusId", statusEnum.getIndex());
		  params.put("policyTradeOrderNo", p.getPolicyTradeOrderNo());
		  params.put("policyNo", p.getInsNo());
		  policyInfoTravelMapper.updatePolicyByOutOrderNoOrderId(params);

		} else {
		  params.put("statusId", statusEnum.getIndex());
		  policyInfoTravelMapper.updatePolicyStatusByOutOrderNoOrderId(params);
		  statusDesc = p.getMsg();
		}
		params = new HashMap<String, Object>();
		params.put("policyOutOrderNo", p.getPolicyOutOrderNo());
		params.put("orderId", orderId);
		PolicyInfoTravel pInfo = policyInfoTravelMapper
		    .findPolicyInfoByOutOrderNoOrderId(params);
		// 创建保单流
		PolicyFlow policyFlow = new PolicyFlow();
		policyFlow.setFlowInsTypeFid(InsTypeEnum.AIR.getIndex());
		policyFlow.setFlowPolicyFid(pInfo.getPolicyId());
		policyFlow.setFlowOperFid(0);
		policyFlow.setFlowPolicyStatusFid(statusEnum.getIndex());
		policyFlow.setFlowPolicyStatus(statusEnum.getName());
		policyFlow.setFlowMemo(statusDesc);
		policyFlowMapper.insertPolicyFlow(policyFlow);

		transactionManager.commit(status);

	  } catch (Exception ex) {
		ex.printStackTrace();
		transactionManager.rollback(status);
	  }
	}
  }

  // 退保
  public BaseJson cancelPolicy(String policyNo, long custId) {
	BaseJson base = new BaseJson();
	base.setOk(false);
	String msg = null;

	// 取得保单信息（状态为投保成功，支付状态为支付成功，起期>当天）
	Map<String, Object> params = new HashMap<String, Object>();
	params.put("custId", custId);
	params.put("policyNo", policyNo);
	PolicyInfo policyInfo = policyInfoMapper.findCanCanceledPolicyByNo(params);
	// 查询余额
	CustInfo adminInfo = custInfoMapper.findUsefulfeeByName("admin");
	if (policyInfo != null
	    && adminInfo != null
	    && adminInfo.getCustUsefulFee().compareTo(
	        policyInfo.getPolicyRealAmount().subtract(
	            policyInfo.getPolicySettleAmount())) >= 0) {
	  BigDecimal usefulFee = adminInfo.getCustUsefulFee();
	  TransactionStatus status = transactionManager.getTransaction(def);
	  try {
		// TODO 通知大后台
		Config config = new Config();
		OEMConfig configFile = config.getConfigFile(ConfigFileEnum.OEMCONFIG,
		    OEMConfig.class);
		SimplePolicyInfo policy = new SimplePolicyInfo();
		policy.setPolicyCustFid(policyInfo.getPolicyCustFid());
		policy.setPolicyNo(policyInfo.getPolicyNo());
		policy.setPolicyOutOrderNo(policyInfo.getPolicyOutOrderNo());
		policy.setPolicyTradeOrderNo(policyInfo.getPolicyTradeOrderNo());
		String xmlRequest = XML.toXML(policy, SimplePolicyInfo.class);
		logger.info(xmlRequest);
		Map<String, String> paramMap = new HashMap<String, String>();
		paramMap.put("content", xmlRequest);
		String xmlResponse = Http.doPost(configFile.getOemPlatform()
		    + "/webservice/cancelpolicy.service", paramMap);
		logger.info(xmlResponse);
		BaseJson response = XML.fromXML(xmlResponse, BaseJson.class);
		if (response != null) {
		  // 修改保单状态、创建保单流、如成功则退款
		  PolicyStatusEnum pStatus = PolicyStatusEnum.SURRENDER_FAILS;
		  if (response.isOk()) {
			pStatus = PolicyStatusEnum.SURRENDER_SUC;
		  }
		  // 修改保单状态
		  params = new HashMap<String, Object>();
		  params.put("statusId", pStatus.getIndex());
		  params.put("policyId", policyInfo.getPolicyId());

		  if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.AIR.getIndex()) {
			policyInfoAirMapper.updatePolicyStatusById(params);
		  } else if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
			  .getIndex()) {
			policyInfoTravelMapper.updatePolicyStatusById(params);
		  }
		  long feeFlowId = 0;
		  // 退保成功则退款
		  if (response.isOk()) {
			// 修改保单费用状态
			params = new HashMap<String, Object>();
			params
			    .put("feeStatusId", PolicyFeeStatusEnum.REFUND_SUC.getIndex());
			params.put("policyId", policyInfo.getPolicyId());

			if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
			    .getIndex()) {
			  policyInfoAirMapper.updatePolicyFeeStatusById(params);
			} else if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
			    .getIndex()) {
			  policyInfoTravelMapper.updatePolicyFeeStatusById(params);
			}

			// 退实际金额到用户帐户余额
			CustInfo custInfo = custInfoMapper.findUsefulfeeById(custId);
			Calendar now = Calendar.getInstance();
			CustFeeFlow feeFlow = new CustFeeFlow();
			feeFlow.setFlowAfterFee(custInfo.getCustUsefulFee().add(
			    policyInfo.getPolicyRealAmount()));
			feeFlow.setFlowBeforeFee(custInfo.getCustUsefulFee());
			feeFlow.setFlowChangedFee(policyInfo.getPolicyRealAmount());
			feeFlow.setFlowChannel(PayChannelEnum.BALANCE.getName());
			feeFlow.setFlowCreditedOn(now.getTime());
			feeFlow.setFlowCustFid(custId);
			feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
			    .getIndex()) {
			  feeFlow.setFlowFor(PayForEnum.POLICY_AIR.getIndex());
			} else if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
			    .getIndex()) {
			  feeFlow.setFlowFor(PayForEnum.POLICY_TRAVEL.getIndex());
			}
			feeFlow.setFlowMemo(policyInfo.getPolicyNo()
			    + FeeTypeEnum.REFUND.getName());
			feeFlow.setFlowOutPayNo(response.getMsg());
			feeFlow.setFlowPayNo(response.getMsg());
			feeFlow.setFlowRelatedFid(policyInfo.getPolicyId());
			feeFlow.setFlowType(FeeTypeEnum.REFUND.getIndex());
			feeFlow.setFlowPlatformId(response.getMsg());
			custFeeFlowMapper.insertCustFeeFlow(feeFlow);
			feeFlowId = feeFlow.getFlowId();

			params = new HashMap<String, Object>();
			params.put("custId", custId);
			params.put("changedFee", policyInfo.getPolicySettleAmount());
			custInfoMapper.updateUsefulfeeById(params);

			// 从ADMIN账户扣分润金额
			if (policyInfo.getPolicyRealAmount().compareTo(
			    policyInfo.getPolicySettleAmount()) > 0) {
			  BigDecimal changedFee = policyInfo.getPolicyRealAmount()
				  .subtract(policyInfo.getPolicySettleAmount());
			  feeFlow = new CustFeeFlow();
			  feeFlow.setFlowAfterFee(usefulFee.subtract(changedFee));
			  feeFlow.setFlowBeforeFee(usefulFee);
			  feeFlow.setFlowChangedFee(changedFee.subtract(changedFee
				  .multiply(new BigDecimal(2))));
			  feeFlow.setFlowChannel(PayChannelEnum.BALANCE.getName());
			  feeFlow.setFlowCreditedOn(now.getTime());
			  feeFlow.setFlowCustFid(adminInfo.getCustId());
			  feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			  if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
				  .getIndex()) {
				feeFlow.setFlowFor(PayForEnum.POLICY_AIR.getIndex());
			  } else if (policyInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
				  .getIndex()) {
				feeFlow.setFlowFor(PayForEnum.POLICY_TRAVEL.getIndex());
			  }

			  feeFlow.setFlowMemo(policyInfo.getPolicyNo()
				  + FeeTypeEnum.DEDUCT.getName());
			  feeFlow.setFlowOutPayNo(response.getMsg());
			  feeFlow.setFlowPayNo(response.getMsg());
			  feeFlow.setFlowRelatedFid(policyInfo.getPolicyId());
			  feeFlow.setFlowType(FeeTypeEnum.DEDUCT.getIndex());
			  feeFlow.setFlowPlatformId(response.getMsg());
			  custFeeFlowMapper.insertCustFeeFlow(feeFlow);

			  params = new HashMap<String, Object>();
			  params.put("custId", adminInfo.getCustId());
			  params.put("changedFee",
				  changedFee.subtract(changedFee.multiply(new BigDecimal(2))));
			  custInfoMapper.updateUsefulfeeById(params);
			}
		  }

		  // 创建保单流
		  PolicyFlow policyFlow = new PolicyFlow();
		  policyFlow.setFlowInsTypeFid(policyInfo.getOrderProductTypeFid());
		  policyFlow.setFlowMemo(response.getMsg());
		  policyFlow.setFlowPolicyFid(policyInfo.getPolicyId());
		  policyFlow.setFlowPolicyStatus(pStatus.getName());
		  policyFlow.setFlowPolicyStatusFid(pStatus.getIndex());
		  policyFlow.setFlowFeeFlowFid(feeFlowId);
		  policyFlowMapper.insertPolicyFlow(policyFlow);

		  transactionManager.commit(status);
		  if (response.isOk())
			base.setOk(true);
		  else {
			base.setMsg(response.getMsg());
		  }
		} else {
		  msg = ControllerPropertyEnum.ORDER_DATA_WRONG.toString();
		}
	  } catch (Exception e) {
		e.printStackTrace();
		transactionManager.rollback(status);
		msg = null;
	  }
	} else
	  msg = ControllerPropertyEnum.ORDER_DATA_WRONG.toString();
	base.setMsg(msg);
	return base;
  }

  // 退款
  public BaseJson refundPolicy(long orderId, long policyId, long custId) {
	BaseJson base = new BaseJson();
	base.setOk(false);
	String msg = null;
	String memo = "";
	// 取得订单信息
	Map<String, Object> params = new HashMap<String, Object>();
	params.put("custId", custId);
	params.put("orderId", orderId);
	OrderInfo orderInfo = orderInfoMapper.findOrderInfoById(params);
	if (orderInfo != null) {
	  memo = orderInfo.getOrderNo();
	  String outNo = null;
	  BigDecimal royaltyFee = new BigDecimal(0);
	  BigDecimal settleFee = new BigDecimal(0);
	  BigDecimal payFee = new BigDecimal(0);
	  params = new HashMap<String, Object>();
	  params.put("custId", custId);
	  params.put("policyId", policyId);
	  params.put("orderId", orderId);
	  if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR.getIndex()) {
		PolicyInfoAir policyInfo = policyInfoAirMapper
		    .findCanRefundPolicyInfoOrderId(params);
		if (policyInfo != null) {
		  outNo = policyInfo.getPolicyOutOrderNo();
		  settleFee = policyInfo.getPolicySettleAmount();
		  payFee = policyInfo.getPolicyRealAmount();
		  royaltyFee = payFee.subtract(settleFee);
		  memo += "," + policyInfo.getPolicyInsuredName();
		}
	  } else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
		  .getIndex()) {
		PolicyInfoTravel policyInfo = policyInfoTravelMapper
		    .findCanRefundPolicyInfoOrderId(params);
		if (policyInfo != null) {
		  outNo = policyInfo.getPolicyOutOrderNo();
		  settleFee = policyInfo.getPolicySettleAmount();
		  payFee = policyInfo.getPolicyRealAmount();
		  royaltyFee = payFee.subtract(settleFee);
		  memo += "," + policyInfo.getPolicyInsuredName();
		}
	  }
	  if (outNo != null) {
		// 查询余额
		CustInfo adminInfo = custInfoMapper.findUsefulfeeByName("admin");
		if (adminInfo != null
		    && adminInfo.getCustUsefulFee().compareTo(royaltyFee) >= 0) {
		  BigDecimal usefulFee = adminInfo.getCustUsefulFee();
		  TransactionStatus status = transactionManager.getTransaction(def);
		  try {
			// TODO 通知大后台
			Config config = new Config();
			OEMConfig configFile = config.getConfigFile(
			    ConfigFileEnum.OEMCONFIG, OEMConfig.class);
			SimplePolicyInfo policy = new SimplePolicyInfo();
			policy.setPolicyCustFid(custId);
			policy.setPolicyOutOrderNo(outNo);
			String xmlRequest = XML.toXML(policy, SimplePolicyInfo.class);
			logger.info(xmlRequest);
			Map<String, String> paramMap = new HashMap<String, String>();
			paramMap.put("content", xmlRequest);
			String xmlResponse = Http.doPost(configFile.getOemPlatform()
			    + "/webservice/refundpolicy.service", paramMap);
			logger.info(xmlResponse);
			BaseJson response = XML.fromXML(xmlResponse, BaseJson.class);
			if (response != null && response.isOk()) {
			  // 修改保单费用状态
			  params = new HashMap<String, Object>();
			  params.put("feeStatusId",
				  PolicyFeeStatusEnum.REFUND_SUC.getIndex());
			  params.put("policyId", policyId);

			  if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
				  .getIndex()) {
				policyInfoAirMapper.updatePolicyFeeStatusById(params);
			  } else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
				  .getIndex()) {
				policyInfoTravelMapper.updatePolicyFeeStatusById(params);
			  }

			  // 退实际金额到用户帐户余额
			  CustInfo custInfo = custInfoMapper.findUsefulfeeById(custId);
			  Calendar now = Calendar.getInstance();
			  CustFeeFlow feeFlow = new CustFeeFlow();
			  feeFlow.setFlowAfterFee(custInfo.getCustUsefulFee().add(payFee));
			  feeFlow.setFlowBeforeFee(custInfo.getCustUsefulFee());
			  feeFlow.setFlowChangedFee(payFee);
			  feeFlow.setFlowChannel(PayChannelEnum.BALANCE.getName());
			  feeFlow.setFlowCreditedOn(now.getTime());
			  feeFlow.setFlowCustFid(custId);
			  feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
			  if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
				  .getIndex()) {
				feeFlow.setFlowFor(PayForEnum.POLICY_AIR.getIndex());
			  } else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
				  .getIndex()) {
				feeFlow.setFlowFor(PayForEnum.POLICY_TRAVEL.getIndex());
			  }
			  feeFlow.setFlowMemo(memo + FeeTypeEnum.REFUND.getName());
			  feeFlow.setFlowOutPayNo(response.getMsg());
			  feeFlow.setFlowPayNo(response.getMsg());
			  feeFlow.setFlowRelatedFid(policyId);
			  feeFlow.setFlowType(FeeTypeEnum.REFUND.getIndex());
			  feeFlow.setFlowPlatformId(response.getMsg());
			  custFeeFlowMapper.insertCustFeeFlow(feeFlow);

			  params = new HashMap<String, Object>();
			  params.put("custId", custId);
			  params.put("changedFee", settleFee);
			  custInfoMapper.updateUsefulfeeById(params);

			  // 从ADMIN账户扣分润金额
			  if (payFee.compareTo(settleFee) > 0) {
				BigDecimal changedFee = royaltyFee;
				feeFlow = new CustFeeFlow();
				feeFlow.setFlowAfterFee(usefulFee.subtract(changedFee));
				feeFlow.setFlowBeforeFee(usefulFee);
				feeFlow.setFlowChangedFee(changedFee.subtract(changedFee
				    .multiply(new BigDecimal(2))));
				feeFlow.setFlowChannel(PayChannelEnum.BALANCE.getName());
				feeFlow.setFlowCreditedOn(now.getTime());
				feeFlow.setFlowCustFid(adminInfo.getCustId());
				feeFlow.setFlowFlag(PaymentStatusEnum.SUC.getIndex());
				if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.AIR
				    .getIndex()) {
				  feeFlow.setFlowFor(PayForEnum.POLICY_AIR.getIndex());
				} else if (orderInfo.getOrderProductTypeFid() == InsTypeEnum.TRAVEL
				    .getIndex()) {
				  feeFlow.setFlowFor(PayForEnum.POLICY_TRAVEL.getIndex());
				}

				feeFlow.setFlowMemo(memo + FeeTypeEnum.DEDUCT.getName());
				feeFlow.setFlowOutPayNo(response.getMsg());
				feeFlow.setFlowPayNo(response.getMsg());
				feeFlow.setFlowRelatedFid(policyId);
				feeFlow.setFlowType(FeeTypeEnum.DEDUCT.getIndex());
				feeFlow.setFlowPlatformId(response.getMsg());
				custFeeFlowMapper.insertCustFeeFlow(feeFlow);

				params = new HashMap<String, Object>();
				params.put("custId", adminInfo.getCustId());
				params
				    .put("changedFee", changedFee.subtract(changedFee
				        .multiply(new BigDecimal(2))));
				custInfoMapper.updateUsefulfeeById(params);
			  }
			  transactionManager.commit(status);

			  base.setOk(true);

			} else {
			  msg = ControllerPropertyEnum.ORDER_DATA_WRONG.toString();
			}
		  } catch (Exception e) {
			e.printStackTrace();
			transactionManager.rollback(status);
			msg = null;
		  }
		} else
		  msg = ControllerPropertyEnum.ORDER_DATA_WRONG.toString();
	  }
	} else
	  msg = ControllerPropertyEnum.ORDER_DATA_WRONG.toString();
	base.setMsg(msg);
	return base;
  }
}
